package edu.buaa.resourceManager.search;

import edu.buaa.resourceManager.vo.CustomProperty;
import edu.buaa.resourceManager.vo.FileEntity;
import edu.buaa.resourceManager.vo.ResourcePath;
import org.ansj.lucene6.AnsjAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;


import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by sjh on 17-5-21.
 */
public class Search
{
    public static final String FIELD_Comment =    "comment";
    public static final String FIELD_EZPComment = "marker";
    public static final String FIELD_SHA512 =     "id";
    public static final String FIELD_Path =       "path";
    public static final String FIELD_Path_ID =    "no";
    public static final String FIELD_Entity_Comment = "content";

    private static Logger log = LoggerFactory.getLogger("Amitabha");
    private Directory directory;
    private Analyzer analyzer;
    private IndexWriter indexWriter;
    private DirectoryReader indexReader;
    private IndexSearcher searcher;

    private static Search me = null;


    public static Search getInstance() {
        if(me==null){
            try {
                me = new Search();
            } catch (IOException e) {
                log.trace("error initialize search service!",e);
                throw new RuntimeException(e);
            }
        }
        return me;
    }

    private Search() throws IOException {
        // Store the index in memory:
//        directory = new RAMDirectory();
        // To store an index on disk, use this instead:
        directory = FSDirectory.open(new File(".","resourceManager.lucenceIndex").toPath());
        analyzer = new AnsjAnalyzer(AnsjAnalyzer.TYPE.index_ansj);
        indexWriter = new IndexWriter(directory, new IndexWriterConfig(analyzer));
    }

    public void addDoc(ResourcePath resourcePath) throws IOException {
        indexWriter.addDocument(toDoc(resourcePath));
        indexWriter.commit();
    }



    public void updateDoc(ResourcePath resourcePath) throws IOException{
        indexWriter.updateDocument(new Term(FIELD_SHA512, resourcePath.getFileEntity().getSha512()), toDoc(resourcePath));
        indexWriter.commit();
    }

    private Document toDoc(ResourcePath file){
        Document doc = new Document();
        doc.add(new Field(FIELD_Path_ID, String.valueOf(file.getId()), TextField.TYPE_STORED));
        doc.add(new Field(FIELD_Comment, file.getComment(), TextField.TYPE_NOT_STORED));
        doc.add(new Field(FIELD_Path, file.getPath(),TextField.TYPE_STORED));
        for(CustomProperty p : file.getProperties()){
            doc.add(new Field(p.getName(), p.getValue(), TextField.TYPE_NOT_STORED));
        }
        FileEntity entity = file.getFileEntity();
        if(entity!=null){
            doc.add(new Field(FIELD_SHA512, file.getFileEntity().getSha512(), TextField.TYPE_STORED));
            doc.add(new Field(FIELD_Entity_Comment, file.getComment(), TextField.TYPE_NOT_STORED));
            for(CustomProperty p : entity.getProperties()){
                if("EZPComment".toLowerCase().equals(p.getName().toLowerCase())){
                    doc.add(new Field(FIELD_EZPComment, p.getValue(), TextField.TYPE_NOT_STORED));
                }else{
                    doc.add(new Field(p.getName(), p.getValue(), TextField.TYPE_NOT_STORED));
                }
            }
        }

        return doc;
    }

    public void close() throws IOException {
        if(indexReader!=null) indexReader.close();
        indexWriter.close();
        directory.close();
    }

    public List<Document> search(String queryStr) throws IOException, ParseException {
        indexReader = DirectoryReader.open(directory);
        searcher = new IndexSearcher(indexReader);
        // Parse a simple query that searches for "text":
        QueryParser parser = new QueryParser(FIELD_Comment, analyzer);
        Query query = parser.parse(queryStr);
        ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
        // Iterate through the results:
        List<Document> result = new ArrayList<Document>();
        for (int i = 0; i < hits.length; i++) {
            Document hitDoc = searcher.doc(hits[i].doc);
            result.add(hitDoc);
            if(i>20) break;
        }
        return result;
    }


    public List<Document> getAll() throws IOException, ParseException {
        indexReader = DirectoryReader.open(directory);
        searcher = new IndexSearcher(indexReader);
        // Parse a simple query that searches for "text":
        Query query = new MatchAllDocsQuery();
        ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
        // Iterate through the results:
        List<Document> result = new ArrayList<Document>();
        for (int i = 0; i < hits.length; i++) {
            Document hitDoc = searcher.doc(hits[i].doc);
            result.add(hitDoc);
            if(i>20) break;
        }
        return result;
    }

//    public static ResourcePath fromDoc(Document doc) throws SQLException {
//        return StoreDB.getInstance().getFileBySha512(doc.get(Search.FIELD_SHA512));
//    }
}
